package com.zzh.camera2.manager

import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Configuration
import android.graphics.ImageFormat
import android.graphics.Matrix
import android.graphics.RectF
import android.graphics.SurfaceTexture
import android.hardware.camera2.*
import android.hardware.camera2.CameraCaptureSession.CaptureCallback
import android.hardware.camera2.params.OutputConfiguration
import android.hardware.camera2.params.SessionConfiguration
import android.media.ImageReader
import android.media.ImageReader.OnImageAvailableListener
import android.os.Build
import android.os.Handler
import android.os.HandlerThread
import android.util.Log
import android.util.Size
import android.view.Surface
import android.view.TextureView.SurfaceTextureListener
import android.view.WindowManager
import androidx.annotation.NonNull
import androidx.annotation.RequiresApi
import com.zzh.camera2.model.CameraParameter
import com.zzh.camera2.model.Const
import com.zzh.camera2.ui.AutoFitTextureView
import com.zzh.camera2.utils.ImageUtils
import com.zzh.camera2.utils.JavaUtils
import com.zzh.camera2.utils.LogUtils

class CameraApi2Manager : ICameraManager {
    companion object {
        val TAG: String = CameraApi2Manager::class.java.simpleName
    }

    /*** 相机管理类 */
    var mCameraManager: CameraManager? = null

    /*** 指定摄像头ID对应的Camera实体对象 */
    var mCameraDevice: CameraDevice? = null

    /**
     * 预览尺寸
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private var mPreviewSize = Size(Const.previewWidth, Const.previewHeight)

    /*** 打开摄像头的ID[CameraDevice]. */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private var mCameraId = CameraCharacteristics.LENS_FACING_FRONT

    /*** 处理静态图像捕获的ImageReader。[ImageReader] */
    private var mImageReader: ImageReader? = null

    /*** 用于相机预览的{@Link CameraCaptureSession}。 */
    private var mCaptureSession: CameraCaptureSession? = null

    /*** [CaptureRequest.Builder]用于相机预览请求的构造器 */
    private var mPreviewRequestBuilder: CaptureRequest.Builder? = null

    /***预览请求, 由上面的构建器构建出来 */
    private var textureView: AutoFitTextureView? = null

    /***判断是否支持闪关灯 */
    private var mFlashSupported = false

    /*** 用于运行不应阻塞UI的任务的附加线程。 */
    private var mBackgroundThread: HandlerThread? = null
    private val maxImages = 2
    private var faceDetectModes: IntArray? = null

    /*** 用于在后台运行任务的[Handler]。 */
    private var mBackgroundHandler: Handler? = null
    private var camera12PreviewCallback: ICameraPreviewCallback? = null
    override fun setPreviewCallback(camera12PreviewCallback: ICameraPreviewCallback) {
        this.camera12PreviewCallback = camera12PreviewCallback
    }

    var previewFormat = ImageFormat.YUV_420_888
    private var isShowCallbackView = CameraParameter.isShowCallbackImage
    var context: Context

    constructor(context: Context) {
        this.context = context.applicationContext
        // 获取CameraManager 相机设备管理器
        mCameraManager = this.context.getSystemService(Context.CAMERA_SERVICE) as CameraManager?
    }

    override fun openCamera(
        textureView: AutoFitTextureView,
        cameraId: Int,
        previewWidth: Int,
        previewHeight: Int,
        previewFormat: Int
    ) {
        if (textureView == null) {
            throw IllegalArgumentException("openCamera textureView is null")
        }

        this.textureView = textureView
        mCameraId = cameraId
        mPreviewSize = Size(previewWidth, previewHeight)
        this.previewFormat = previewFormat
        if (this.textureView!!.isAvailable)
            openCamera(textureView.width, textureView.height)
        else
            this.textureView!!.surfaceTextureListener = textureListener
    }

    override fun openCamera(
        cameraId: Int,
        previewWidth: Int,
        previewHeight: Int,
        previewFormat: Int
    ) {
        mCameraId = cameraId
        mPreviewSize = Size(previewWidth, previewHeight)
        this.previewFormat = previewFormat
        openCamera(previewWidth, previewHeight)
    }


    override fun startPreview() {
    }

    // 不做处理
    override fun stopPreview() {

    }

    override fun releaseCamera() {
        closeCamera()
    }

    /**
     * 预览请求构建器, 用来构建"预览请求"(下面定义的)通过pipeline发送到Camera device
     * 这是[ImageReader]的回调对象。 当静止图像准备保存时，将会调用“onImageAvailable”。
     * 当加上mPreviewRequestBuilder!!.addTarget(mImageReader!!.surface) 代码后，会持续回调
     */
    private val mOnImageAvailableListener = OnImageAvailableListener { reader ->
        // 必须加image获取和image关闭方法，才不会导致预览卡死。
        if (reader != null) {
            val image = reader.acquireLatestImage()
            if (!isShowCallbackView) {
                image.close()
            } else if (image != null) {
                var byteArray: ByteArray? = null
                var imageFormat = 0
                if (previewFormat == ImageFormat.YV12 || previewFormat == ImageFormat.YUV_420_888) {
                    imageFormat = Const.previewImageFormatNV21
                    byteArray = ImageUtils.getBytesFromImageToNV21(image)
//                    byteArray = ImageUtils.NV21_mirror(byteArray!!, Const.previewWidth, Const.previewHeight)
                } else {
                    if (image.planes.isNotEmpty()) {
                        val buffer = image.planes[0].buffer
                        val bytes = ByteArray(buffer.remaining())
                        buffer[bytes]
                        if (previewFormat != ImageFormat.RAW10) {
                            byteArray = bytes.clone()
                        } else {
                            imageFormat = Const.previewImageFormatRAW16
                            byteArray = JavaUtils.transformRAW10ToRAW16(
                                bytes.clone(),
                                mPreviewSize.width,
                                mPreviewSize.height
                            )
                        }
                    }
                    image.close()
                }
                if (camera12PreviewCallback != null && byteArray != null)
                    camera12PreviewCallback!!.onPreviewFrame(byteArray, imageFormat, this)
            }
        }
    }

    /*** [CameraDevice.StateCallback]打开指定摄像头回调[CameraDevice] */
    private val mStateCallback: CameraDevice.StateCallback =
        @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
        object : CameraDevice.StateCallback() {
            override fun onOpened(@NonNull cameraDevice: CameraDevice) {
                LogUtils.d(
                    TAG,
                    "mStateCallback onOpened thread=${Thread.currentThread()} cameraid=$mCameraId"
                )
                mCameraDevice = cameraDevice
                createCameraPreview()
            }

            override fun onDisconnected(@NonNull cameraDevice: CameraDevice) {
                LogUtils.d(TAG, "mStateCallback onDisconnected id =${cameraDevice.id}")
                mCameraDevice = cameraDevice
                releaseCamera()
            }

            override fun onError(@NonNull cameraDevice: CameraDevice, error: Int) {
                LogUtils.d(TAG, "mStateCallback onError id =${cameraDevice.id}, error=$error")
                mCameraDevice = cameraDevice
                releaseCamera()
            }
        }

    /**
     * TextureView 生命周期响应
     */
    private val textureListener: SurfaceTextureListener = object : SurfaceTextureListener {
        //创建
        @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
        override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
            openCamera(width, height)
        }

        //尺寸改变
        @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
        override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {
            configureTransform(width, height)
        }

        //销毁
        override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
            return false
        }

        //更新
        override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {}
    }

    /**
     * 打开指定摄像头ID的相机
     */
    @SuppressLint("MissingPermission")
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private fun openCamera(viewWidth: Int, viewHeight: Int) {
        try {
            startBackgroundThread()

            autoRatioTextureView()
            configureTransform(viewWidth, viewHeight)

            if (mImageReader == null) {
                // 创建一个ImageReader对象，用于获取摄像头的图像数据,maxImages是ImageReader一次可以访问的最大图片数量
                mImageReader = ImageReader.newInstance(
                    mPreviewSize.width,
                    mPreviewSize.height,
                    previewFormat,
                    maxImages
                )
                mImageReader!!.setOnImageAvailableListener(
                    mOnImageAvailableListener,
                    mBackgroundHandler
                )
            }
            mCameraManager!!.openCamera(mCameraId.toString(), mStateCallback, mBackgroundHandler)
            printCameraInfo()
        } catch (e: CameraAccessException) {
            e.printStackTrace()
        } catch (e1: Exception) {
            e1.printStackTrace()
        }
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private fun printCameraInfo() {
        LogUtils.d(TAG, "printCameraInfo openCamera current camera id=$mCameraId")
        val ids = mCameraManager!!.cameraIdList
        if (ids != null) {
            for (id in ids.indices) {
                LogUtils.d(TAG, "openCamera support id[$id]=${ids[id]}")
            }
        }

        val characteristics = mCameraManager!!.getCameraCharacteristics(mCameraId.toString() + "")
        //检查是否支持闪光灯
        val available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)
        mFlashSupported = available ?: false
        LogUtils.d(TAG, "openCamera mFlashSupported=$mFlashSupported")

        val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
        if (map != null) {
            val previewSizes = map.getOutputSizes(SurfaceTexture::class.java)//获取预览尺寸
            for (i in previewSizes.indices)
                LogUtils.d(TAG, "openCamera previewSizes[$i]=${previewSizes[i]}")
            val captureSizes = map.getOutputSizes(ImageFormat.JPEG)//获取拍照尺寸
            for (i in captureSizes.indices)
                LogUtils.d(TAG, "openCamera captureSizes[$i]=${captureSizes[i]}")
        }
        val cOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)//获取相机角度
        LogUtils.d(TAG, "openCamera 相机角度 cOrientation=${cOrientation}")
        val cRect = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE)//获取成像区域
        LogUtils.d(TAG, "openCamera 成像区域 cRect=${cRect}")
        val cPixelSize =
            characteristics.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE)//获取成像尺寸，同上
        LogUtils.d(TAG, "openCamera 成像尺寸 cPixelSize=${cPixelSize}")
        //可用于判断是否支持人脸检测，以及支持到哪种程度
        faceDetectModes =
            characteristics[CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES] //支持的人脸检测模式
        if (faceDetectModes != null) {
            for (i in 0 until faceDetectModes!!.size)
                LogUtils.d(TAG, "openCamera 支持的人脸检测模式 faceDetectModes[$i]=${faceDetectModes!![i]}")
        }
        val maxFaceCount =
            characteristics[CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT]!! //支持的最大检测人脸数量
        LogUtils.d(TAG, "openCamera 支持的最大检测人脸数量 maxFaceCount=${maxFaceCount}")
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private fun autoRatioTextureView() {
        if (this.textureView == null) {
            return
        }
        // We fit the aspect ratio of TextureView to the size of preview we picked.
        val orientation: Int = textureView!!.getResources().getConfiguration().orientation
        Log.i("TAG", "orientation=$orientation")
        // 横竖屏都是宽更短，高更长
        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            textureView!!.setAspectRatio(
                mPreviewSize.height, mPreviewSize.width
            )
        } else {
            textureView!!.setAspectRatio(
                mPreviewSize.height, mPreviewSize.width
            )
        }
    }

    /**
     * Configures the necessary [android.graphics.Matrix] transformation to `mTextureView`.
     * This method should be called after the camera preview size is determined in
     * setUpCameraOutputs and also the size of `mTextureView` is fixed.
     * @param viewWidth  The width of `mTextureView`
     * @param viewHeight The height of `mTextureView`
     */
    private fun configureTransform(viewWidth: Int, viewHeight: Int) {
        if (this.textureView == null) {
            return
        }
        val rotation =
            (this.context.getSystemService(Context.WINDOW_SERVICE) as WindowManager?)!!.defaultDisplay.rotation
        Log.i("TAG", "rotation=$rotation, camera id=$mCameraId")
        val matrix = Matrix()
        val viewRect = RectF(0f, 0f, viewWidth.toFloat(), viewHeight.toFloat())
        val bufferRect = RectF(0f, 0f, mPreviewSize.height.toFloat(), mPreviewSize.width.toFloat())
        val centerX = viewRect.centerX()
        val centerY = viewRect.centerY()
        if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY())
            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL)
            val scale = Math.max(
                viewHeight.toFloat() / mPreviewSize.height,
                viewWidth.toFloat() / mPreviewSize.width
            )
            matrix.postScale(scale, scale, centerX, centerY)
            matrix.postRotate((90 * (rotation - 2)).toFloat(), centerX, centerY)
        } else if (Surface.ROTATION_180 == rotation) {
            matrix.postRotate(180f, centerX, centerY)
        }
        textureView!!.setTransform(matrix)
    }

    /**
     * 创建预览对话
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private fun createCameraPreview() {
        if (this.context == null) {
            return
        }
        try {
            //创建预览请求构建器
            mPreviewRequestBuilder =
                mCameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
            //设置实时帧数据接收，不设置的话onImageAvailable不会回调数据，只有拍照时回调
            mPreviewRequestBuilder!!.addTarget(mImageReader!!.surface)
            var surface: Surface? = null
            if (this.textureView != null) {
                // 获取texture实例
                val surfaceTexture: SurfaceTexture = textureView!!.surfaceTexture!!
                //我们将默认缓冲区的大小配置为我们想要的相机预览的大小。
                surfaceTexture.setDefaultBufferSize(mPreviewSize.width, mPreviewSize.height)
                // 用来开始预览的输出surface
                surface = Surface(surfaceTexture)
                //将TextureView的Surface作为相机的预览显示输出
                mPreviewRequestBuilder!!.addTarget(surface)
            }

            //设置人脸检测级别，设置为非关闭，才能检测人脸
            mPreviewRequestBuilder!!.set(
                CaptureRequest.STATISTICS_FACE_DETECT_MODE,
                getFaceDetectMode()
            )
            //3A--->auto
            mPreviewRequestBuilder!!.set(
                CaptureRequest.CONTROL_MODE,
                CameraMetadata.CONTROL_MODE_AUTO
            )
            //3A
            mPreviewRequestBuilder!!.set(
                CaptureRequest.CONTROL_AF_MODE,
                CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_VIDEO
            )
            mPreviewRequestBuilder!!.set(
                CaptureRequest.CONTROL_AE_MODE,
                CameraMetadata.CONTROL_AE_MODE_ON
            )
            mPreviewRequestBuilder!!.set(
                CaptureRequest.CONTROL_AWB_MODE,
                CameraMetadata.CONTROL_AWB_MODE_AUTO
            )

            // 在打开两个相机，且不用控件显示预览时，用这个方法会导致有一个相机无法正常关闭
            if (Build.VERSION.SDK_INT >= 28) {
                // use no deprecated function @{
                val sessionType = SessionConfiguration.SESSION_REGULAR
                val outputConfigArrays = ArrayList<OutputConfiguration>()
                val outputConfiguration2 = OutputConfiguration(mImageReader!!.surface)
                outputConfigArrays.add(outputConfiguration2)
                if (surface != null) {
                    val outputConfiguration1 = OutputConfiguration(surface!!)
                    outputConfigArrays.add(outputConfiguration1)
                }

                val executor = this.context.mainExecutor
                val captureStateCallback = object : CameraCaptureSession.StateCallback() {
                    override fun onConfigured(@NonNull cameraCaptureSession: CameraCaptureSession) {
                        // 相机关闭时, 直接返回
                        if (null == mCameraDevice) {
                            return
                        }
                        //会话准备就绪后，我们开始显示预览。
                        // 会话可行时, 将构建的会话赋给field
                        mCaptureSession = cameraCaptureSession
                        // 开始预览
                        mCaptureSession!!.setRepeatingRequest(
                            mPreviewRequestBuilder!!.build(),
                            mCaptureCallback,
                            mBackgroundHandler
                        )
                        //设置闪关灯模式
//                    setFlashMode(CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH)
                    }

                    override fun onConfigureFailed(@NonNull cameraCaptureSession: CameraCaptureSession) {
                        LogUtils.d(TAG, "onConfigureFailed")
                    }
                }
                val sessionConfiguration = SessionConfiguration(
                    sessionType,
                    outputConfigArrays,
                    executor,
                    captureStateCallback
                )
                //在这里，我们为相机预览创建一个CameraCaptureSession。
                mCameraDevice!!.createCaptureSession(sessionConfiguration)
                // @}
            } else {
                val listSurface = ArrayList<Surface>()
                listSurface.add(mImageReader!!.surface)
                if (surface != null) {
                    listSurface.add(surface)
                }
                val stateCallback: CameraCaptureSession.StateCallback =
                    object : CameraCaptureSession.StateCallback() {
                        override fun onConfigured(@NonNull cameraCaptureSession: CameraCaptureSession) {
                            // 相机关闭时, 直接返回
                            if (null == mCameraDevice) {
                                return
                            }
                            //会话准备就绪后，我们开始显示预览。
                            // 会话可行时, 将构建的会话赋给field
                            mCaptureSession = cameraCaptureSession
                            //相机预览应该连续自动对焦。
//                        mPreviewRequestBuilder!!.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO)
                            // 开始预览
                            mCaptureSession!!.setRepeatingRequest(
                                mPreviewRequestBuilder!!.build(),
                                mCaptureCallback,
                                mBackgroundHandler
                            )
                            //设置闪关灯模式
//                    setFlashMode(CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH)
                        }

                        override fun onConfigureFailed(@NonNull cameraCaptureSession: CameraCaptureSession) {
                            LogUtils.d(TAG, "onConfigureFailed")
                        }
                    }
                //在这里，我们为相机预览创建一个CameraCaptureSession。
                mCameraDevice!!.createCaptureSession(listSurface, stateCallback, mBackgroundHandler)
            }
        } catch (e: CameraAccessException) {
            e.printStackTrace()
        }
    }

    /**
     * 获取支持的最高人脸检测级别
     * @return
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private fun getFaceDetectMode(): Int {
        return if (faceDetectModes == null) {
            CaptureRequest.STATISTICS_FACE_DETECT_MODE_FULL
        } else {
            faceDetectModes!!.get(faceDetectModes!!.size - 1)
        }
    }

    /**
     * Closes the current [CameraDevice].
     * 关闭正在使用的相机
     */
    private fun closeCamera() {
        // 关闭拍照处理器
        if (null != mImageReader) {
            try {
                mImageReader!!.setOnImageAvailableListener(null, null)
                mImageReader!!.close()
                mImageReader = null
            } catch (e: Exception) {
                Log.e(TAG, "closeCamera close imagereader error = " + e.message)
            }
        }
        // 关闭捕获会话
        if (null != mCaptureSession) {
            try {
                mCaptureSession!!.close()
                mCaptureSession = null
            } catch (cameraAccessException: CameraAccessException) {
                Log.e(
                    TAG,
                    "closeCamera mCaptureSession close cameraAccessException = " + cameraAccessException.message
                )
            } catch (e1: Exception) {
                Log.e(TAG, "closeCamera mCaptureSession close E1 = " + e1.message)
            }
        }
        // 关闭当前相机
        if (null != mCameraDevice) {
            try {
                mCameraDevice!!.close()
                mCameraDevice = null
            } catch (e: Exception) {
                Log.e(TAG, "closeCamera mCameraDevice close E = " + e.message)
            }
        }
        stopBackgroundThread()
    }

    /**
     * 初试化拍照线程
     */
    private fun startBackgroundThread() {
        mBackgroundThread = HandlerThread("Camera Background")
        mBackgroundThread!!.start()
        mBackgroundHandler = Handler(mBackgroundThread!!.looper)
    }

    private fun stopBackgroundThread() {
        if (mBackgroundThread != null && mBackgroundHandler != null) {
            mBackgroundHandler!!.removeCallbacksAndMessages(null)
            mBackgroundHandler = null

            mBackgroundThread!!.quitSafely()
            mBackgroundThread = null
        }
    }

    /**
     * A [CameraCaptureSession.CaptureCallback] that handles events related to JPEG capture.
     */
    private val mCaptureCallback: CaptureCallback = @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    object : CaptureCallback() {

        override fun onCaptureProgressed(
            @NonNull session: CameraCaptureSession,
            @NonNull request: CaptureRequest,
            @NonNull partialResult: CaptureResult
        ) {
        }

        override fun onCaptureCompleted(
            @NonNull session: CameraCaptureSession,
            @NonNull request: CaptureRequest,
            @NonNull result: TotalCaptureResult
        ) {
            /*val faces = result.get(CaptureResult.STATISTICS_FACES)
            LogUtils.d(TAG, "人脸个数:" + faces?.size)
            if (faces != null) {
                for (f in faces.indices) {
                    LogUtils.d(TAG, "人脸[$f]id:" + faces[f].id)
                    //人脸检测坐标基于相机成像画面尺寸以及坐标原点。此处进行比例换算
                    LogUtils.d(TAG, "人脸[$f]bounds:" + faces[f].bounds)
                    LogUtils.d(TAG, "人脸[$f]leftEyePosition:" + faces[f].leftEyePosition)
                    LogUtils.d(TAG, "人脸[$f]rightEyePosition:" + faces[f].rightEyePosition)
                    LogUtils.d(TAG, "人脸[$f]score:" + faces[f].score)
                }
            }*/
        }
    }
}